package handler

import (
	"context"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/golang/protobuf/ptypes/wrappers"
	questC "kop/modules/quest/client"
	"kop/modules/quest/configuration/questtype"

	"kop/framework/broker"
	context2 "kop/framework/context"
	"kop/framework/errors"
	"kop/libs/database"
	"kop/modules/achievement/configuration"
	"kop/modules/achievement/configuration/a_type"
	"kop/modules/achievement/models"
	"kop/pb"
	"kop/pb/service"

	awardM "kop/modules/award/models"
)

type AchievementServiceHandler struct {
	context2.Context
}

func (h *AchievementServiceHandler) GetAchievements(ctx context.Context, _ *empty.Empty, resp *pb.Achievements) error {

	var role = pb.Role{RoleID: h.GetRoleID(ctx)}
	var achievements = models.GetAchievements(role.RoleID)

	resp.Achievements = make([]*pb.Achievement, 0, len(configuration.Configs))

	for _, conf := range configuration.Configs {

		var value, finish = int64(0), false
		for _, v := range achievements {
			if v.AType == conf.Type {
				value = v.Value
				for _, ID := range v.IDs {
					if ID == conf.ID {
						finish = true
					}
				}
			}
		}

		resp.Achievements = append(resp.Achievements, &pb.Achievement{
			ID:     conf.ID,
			Type:   int32(conf.Type),
			Value:  value,
			Value2: conf.Value,
			Finish: finish,
			Points: conf.Point,
			Award:  awardM.RandAward(&role, conf.AwardID),
		})
	}

	return nil
}

func (h *AchievementServiceHandler) GetAchievement(ctx context.Context, req *wrappers.Int32Value, resp *wrappers.Int64Value) error {

	var data, err = models.GetOne(database.DB, h.GetRoleID(ctx), a_type.Type(req.Value))
	if err == nil {
		resp.Value = data.Value
	}

	return err
}

func (h *AchievementServiceHandler) GetAward(ctx context.Context, req *wrappers.Int32Value, resp *pb.Award) (err error) {

	var roleID = h.GetRoleID(ctx)
	var conf = configuration.GetByAchievementID(req.Value)

	data, err := models.GetOne(database.DB, roleID, conf.Type)
	if err != nil {
		return err
	}

	for _, ID := range data.IDs {
		if ID == conf.ID {
			return errors.ParamError
		}
	}

	if data.Value < conf.Value {
		return errors.ParamError
	}

	var session = database.DB.Begin()

	defer func() {
		if r := recover(); r != nil {
			err = r.(error)
		}
		if err != nil {
			session.Rollback()
		}
	}()

	data.IDs = append(data.IDs, conf.ID)
	if err := models.Save(session, data); err != nil {
		return err
	}

	data2, err := models.GetOne(session, roleID, a_type.FinishNum)
	if err != nil {
		return err
	}

	data2.Value += int64(conf.Point)
	if err := models.Save(session, data2); err != nil {
		return err
	}

	if err := session.Commit().Error; err != nil {
		return err
	}

	*resp = *awardM.RandAward(&pb.Role{RoleID: roleID}, conf.AwardID)
	return awardM.SendAward(&pb.Role{RoleID: roleID}, resp)
}

func (h *AchievementServiceHandler) SetNumber(_ context.Context, req *service.AchievementRequest, _ *empty.Empty) error {

	var Type = a_type.Type(req.Type)

	data, err := models.GetOne(database.DB, req.RoleID, Type)
	if err != nil {
		return err
	}

	data.Value = req.Number
	err = models.Save(database.DB, data)
	if err == nil {

		_ = broker.RolePublish(req.RoleID, pb.WsCode_CodeAchievement, &pb.CodeActivityData{Type: req.Type, Value: data.Value})
	}
	return err
}

func (h *AchievementServiceHandler) AddNumber(_ context.Context, req *service.AchievementRequest, _ *empty.Empty) error {

	var Type = a_type.Type(req.Type)

	data, err := models.GetOne(database.DB, req.RoleID, Type)
	if err != nil {
		return err
	}

	data.Value += req.Number
	err = models.Save(database.DB, data)
	if err == nil {

		_ = broker.RolePublish(req.RoleID, pb.WsCode_CodeAchievement, &pb.CodeActivityData{Type: req.Type, Value: data.Value})

		var t questtype.QuestType

		switch a_type.Type(req.Type) {

		case a_type.Employ:
			t = questtype.Employ

		case a_type.Bar:
			t = questtype.Bar

		case a_type.Date:
			t = questtype.Date

		case a_type.Train:
			t = questtype.Train

		case a_type.Event:
			t = questtype.Event

		case a_type.Conquer:
			t = questtype.Conquer

		case a_type.GuildBuild:
			t = questtype.GuildBuild

		default:
			return nil
		}

		_, _ = questC.QuestService.SetNumber(context.Background(), &service.QuestSetRequest{RoleID: req.RoleID, Type: int32(t), Number: data.Value})

	}
	return err
}
